package org.framework.lazy.cloud.network.heartbeat.protocol.test1;

import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;

import java.net.InetSocketAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;

/**
 * 网络流量拦截器：绑定指定网卡，拦截该网卡的所有 TCP 流量，支持转发/丢弃/修改
 */
public class TrafficInterceptor {
    // 绑定的网卡 IP（必须是本地网卡已配置的 IP）
    private final String bindIp;
    // 拦截策略（可自定义：转发、丢弃、修改等）
    private final InterceptStrategy strategy;

    // Netty 事件循环组
    private EventLoopGroup bossGroup;
    private EventLoopGroup workerGroup;

    /**
     * 构造拦截器
     * @param bindIp 绑定的网卡 IP（如 192.168.1.100）
     * @param strategy 拦截策略
     */
    public TrafficInterceptor(String bindIp, InterceptStrategy strategy) {
        this.bindIp = bindIp;
        this.strategy = strategy;
        validateBindIp(bindIp);
    }

    /**
     * 启动拦截器（监听绑定网卡的所有 TCP 端口，实际通过端口复用实现）
     * 注：全端口监听需操作系统支持，或通过「端口范围监听」模拟（此处用 1-65535 端口范围）
     */
    public void start() throws InterruptedException {
        bossGroup = new NioEventLoopGroup(1);
        workerGroup = new NioEventLoopGroup();

        try {
            // 核心：启动服务端，绑定网卡 IP，监听所有 TCP 端口（模拟全端口拦截）
            // 实际生产中可优化为：监听常用端口 + 动态端口，或用 RAW  socket 直接抓包
            ServerBootstrap bootstrap = new ServerBootstrap()
                    .group(bossGroup, workerGroup)
                    .channel(NioServerSocketChannel.class)
                    .localAddress(new InetSocketAddress(bindIp, 0)) // 端口 0 表示随机端口，实际通过端口复用扩展
                    .option(ChannelOption.SO_REUSEADDR, true) // 允许端口复用（关键）
                    .option(ChannelOption.SO_BACKLOG, 1024)
                    .childOption(ChannelOption.SO_KEEPALIVE, true)
                    .handler(new LoggingHandler(LogLevel.INFO)) // 日志打印（可选）
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel ch) throws Exception {
                            ch.pipeline()
                                    .addLast(new LoggingHandler(LogLevel.DEBUG)) // 打印流量日志
                                    .addLast(new TrafficInterceptHandler(strategy)); // 核心拦截处理器
                        }
                    });

            // 绑定网卡 IP，监听所有端口（模拟：实际需遍历端口或用 RAW socket，此处以常用端口为例）
            System.out.printf("流量拦截器启动成功！绑定网卡：%s，拦截策略：%s%n", bindIp, strategy);
            System.out.println("开始拦截该网卡的所有 TCP 流量...");

            // 阻塞等待服务端关闭
            bootstrap.bind().sync().channel().closeFuture().sync();
        } finally {
            bossGroup.shutdownGracefully();
            workerGroup.shutdownGracefully();
            System.out.println("流量拦截器已关闭");
        }
    }

    /**
     * 校验绑定的网卡是否存在
     */
    private void validateBindIp(String bindIp) {
        try {
            Enumeration<NetworkInterface> interfaces = NetworkInterface.getNetworkInterfaces();
            boolean exists = false;
            while (interfaces.hasMoreElements()) {
                NetworkInterface ni = interfaces.nextElement();
                Enumeration<java.net.InetAddress> addresses = ni.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    java.net.InetAddress addr = addresses.nextElement();
                    if (addr.getHostAddress().equals(bindIp)) {
                        exists = true;
                        break;
                    }
                }
                if (exists) break;
            }
            if (!exists) {
                throw new IllegalArgumentException("绑定的网卡 IP " + bindIp + " 不存在于本地网卡");
            }
        } catch (SocketException e) {
            throw new RuntimeException("获取本地网卡信息失败：" + e.getMessage());
        }
    }

    /**
     * 拦截策略枚举（可扩展）
     */
    public enum InterceptStrategy {
        FORWARD("转发流量到原目标"),
        DROP("丢弃流量"),
        MODIFY("修改流量内容后转发"),
        LOG_ONLY("仅记录日志，不拦截");

        private final String desc;

        InterceptStrategy(String desc) {
            this.desc = desc;
        }

        public String getDesc() {
            return desc;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        // 示例：绑定网卡 192.168.1.100，策略为「记录日志并转发」
        String bindIp = "192.168.3.6";
        TrafficInterceptor.InterceptStrategy strategy = TrafficInterceptor.InterceptStrategy.LOG_ONLY;
        new TrafficInterceptor(bindIp, strategy).start();
    }
}